﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpHomeEngine;
using System.Threading;

namespace Insteon.Commands
{
    internal abstract class Command
    {
        protected byte[] buffer;
        internal DateTime SentTime = DateTime.MaxValue;
        internal readonly UInt64 Number = 0;
        private static UInt64 NumberGen = 0;
        
        //use these if you want. not needed really.
        internal Boolean? ModemCompleted = null;
        internal Boolean? DeviceCompleted = null;
        internal Messages.Message ModemResponse = null;
        internal Messages.Message DeviceResponse = null;

        internal Object Value; //a value accociated with the command
        //internal SharpHomeEngine.Request4TagState RequestTagState = null;
        //internal SharpHomeEngine.Request4TagStateChange RequestTagStateChange = null;

        internal SharpHomeEngine.Request4DeviceInterface Request = null;
        internal Requests.InsteonRequest InsteonRequest = null;

        internal AutoResetEvent AutoResetEvent; //my new favorite magic .net class
        
        internal bool isComplete = false;
        internal bool isSuccessful = false;

        public Command()
        {
            NumberGen++;
            Number = NumberGen;
        }

        internal byte[] Buffer
        {
            get
            {
                return buffer;
            }
        }


        /// <summary>
        /// All commands should know what sort of responses are expected.
        /// Call Succeed() Fail() if your responses are finished.
        /// return true only if the message was a response for the command.
        /// return false is the message was not a reponse for the command.
        /// true and false have NOTHING to do wit success or failure.
        /// see StandardCommand for a more polished example.
        /// </summary>
        /// <param name="Message"></param>
        /// <returns></returns>
        internal abstract bool IsResponse(Messages.Message Message);


        internal void Wait()
        {
            AutoResetEvent = new AutoResetEvent(false);
            AutoResetEvent.WaitOne(1000);
        }

        internal void Succeed()
        {
            isComplete = true;
            isSuccessful = true;
            UnBlock();
        }

        internal void Fail()
        {
            isComplete = true;
            isSuccessful = false;
            UnBlock();
        }

        internal void Error()
        {
            isComplete = false;
            isSuccessful = false;
            UnBlock();
        }

        internal void UnBlock()
        {
            if (AutoResetEvent != null)
            {
                AutoResetEvent.Set();
                AutoResetEvent = null;
            }
        }

        public override string ToString()
        {
            return PrintCommonMessage(SentTime, Number, this, null, null, null, 0, 0, null);
        }

        private string BufferString()
        {
            StringBuilder sb = new StringBuilder();
            foreach (byte byt in buffer)
            {
                sb.Append(string.Format("{0:x2} ", byt));
            }
            return sb.ToString();
        }

        internal static String PrintCommonMessage(DateTime Time, UInt64 Number, Command Command, InsteonAddress To, InsteonAddress From, Flags Flags, byte Command1, byte Command2, ResponseStatus Status)
        {
            return string.Format("{0}  {1:0000} {2,-20} (to:{3,-8}) (fr:{4,-8}) ({5}) (c1:{6,2:x} c2:{7,2:x}) {8,-3} : {9}", Time.ToString("HHmmss.fff"), Number, Command.GetType().Name, To, From, Flags, Command1, Command2, Status, Command.BufferString());
        }
    }
}
